//
// Created by WenYF on 2016/11/2.
//

#include "buffer.h"

typedef struct ifbuffer_struct {
    int position;
    int limit;
    int mark;
    int size;
    byte *data;
    BOOL flip;
} ifbuffer;

// 构造
void* if_buffer_new(int size) {
    if (size < 0) {
        return NULL;
    } else {
        int i;
        ifbuffer *buffer = (ifbuffer*) malloc (sizeof(ifbuffer));
        buffer->data = (byte*) malloc (sizeof(byte) * size);
        buffer->size = size;
        memset(buffer->data, 0, sizeof(byte) * size);

        if_buffer_clear(buffer);
        return buffer;
    }
}
// 释放
void if_buffer_delete(void *buf) {
    if (!buf) {
        return;
    } else {
        ifbuffer *buffer = (ifbuffer*)buf;
		if (buffer->data) {
			free(buffer->data);
		}
		free(buffer);
    }
}
// return all data array
byte* if_buffer_array(void *buf) {
    if (!buf) {
        return NULL;
    } else {
        ifbuffer *buffer = (ifbuffer*)buf;
        return buffer->data;
    }
}
// limit - position
int if_buffer_remaining(void *buf) {
    if (!buf) {
        return 0;
    } else {
        ifbuffer *buffer = (ifbuffer*)buf;
        return buffer->limit - buffer->position;
    }
}
// 是否还有数据
BOOL if_buffer_hasRemaining(void *buf) {
    if (!buf) {
        return FALSE;
    } else {
        ifbuffer *buffer = (ifbuffer*)buf;
        return (buffer->limit - buffer->position) > 0 ? TRUE : FALSE;
    }
}
// position ++
void if_buffer_put(void *buf, byte one) {
    if (!buf) {
        return;
    } else {
        ifbuffer *buffer = (ifbuffer*)buf;
        buffer->data[buffer->position++] = one;
    }
}
// position += length
void if_buffer_putBytes(void *buf, byte *data, int length) {
    if (!buf) {
        return;
    } else {
        int i;
        ifbuffer *buffer = (ifbuffer*)buf;
        for (i = 0; i < length && buffer->position < buffer->limit; i++) {
            buffer->data[buffer->position++] = data[i];
        }
    }
}
// position 置为 mark
void if_buffer_reset(void *buf) {
    if (!buf) {
        return;
    } else {
        ifbuffer *buffer = (ifbuffer*)buf;
        buffer->position = buffer->mark;
    }
}
// mark = -1, position = 0
void if_buffer_rewind(void *buf) {
    if (!buf) {
        return;
    } else {
        ifbuffer *buffer = (ifbuffer*)buf;
        buffer->mark = -1;
        buffer->position = 0;
    }
}
// mark = -1, position = 0, limit = size
void if_buffer_clear(void *buf) {
    if (!buf) {
        return;
    } else {
        ifbuffer *buffer = (ifbuffer*)buf;
        buffer->mark = -1;
        buffer->position = 0;
        buffer->limit = buffer->size;
        buffer->flip = FALSE;
    }
}
// mark = position
void if_buffer_mark(void *buf) {
    if (!buf) {
        return;
    } else {
        ifbuffer *buffer = (ifbuffer*)buf;
        buffer->mark = buffer->position;
    }
}
// limit = position, position = 0, mark = -1
void if_buffer_flip(void *buf) {
    if (!buf) {
        return;
    } else {
        ifbuffer *buffer = (ifbuffer*)buf;
        buffer->limit = buffer->position;
        buffer->position = 0;
        buffer->mark = -1;
        buffer->flip = TRUE;
    }
}

static void showNotFlipNotice(ifbuffer *buffer) {
    if (!buffer->flip) {
        logW("do you forget call flip()? ignore if you have done it!");
    }
}

// position++
byte if_buffer_get(void *buf) {
    if (!buf) {
        return 0;
    } else {
        ifbuffer *buffer = (ifbuffer*)buf;
        showNotFlipNotice(buffer);
        if (buffer->position >= buffer->limit) {
            return 0;
        } else {
            return buffer->data[buffer->position++];
        }
    }
}
// position += 2
short if_buffer_getShort(void *buf) {
    if (!buf) {
        return 0;
    } else {
        ifbuffer *buffer = (ifbuffer*)buf;
        showNotFlipNotice(buffer);
        if (buffer->position + 1 >= buffer->limit) {
            return 0;
        } else {
            short st = (short)0;
            short h = buffer->data[buffer->position++];
            short l = buffer->data[buffer->position++];
            st = st | (h << 8);
            st = st | l;

            return st;
        }
    }
}
// position += 4
int if_buffer_getInt(void *buf) {
    if (!buf) {
        return 0;
    } else {
        ifbuffer *buffer = (ifbuffer*)buf;
        showNotFlipNotice(buffer);
        if (buffer->position + 3 >= buffer->limit) {
            return 0;
        } else {
            int it = 0;
            int hh = buffer->data[buffer->position++];
            int hl = buffer->data[buffer->position++];
            int lh = buffer->data[buffer->position++];
            int ll = buffer->data[buffer->position++];
            it = it | (hh << 24);
            it = it | (hl << 16);
            it = it | (lh << 8);
            it = it | ll;

            return it;
        }
    }
}
// position += length
void if_buffer_getBytes(void *buf, byte *data, int length) {
    if (!buf) {
        return;
    } else {
        int i;
        ifbuffer *buffer = (ifbuffer*)buf;
        showNotFlipNotice(buffer);
        for (i = 0; i < length && buffer->position < buffer->limit; i++) {
            data[i] = buffer->data[buffer->position++];
        }
    }
}

// set position
void if_buffer_setPosition(void *buf, int position) {
    if (!buf) {
        return;
    } else {
        ifbuffer *buffer = (ifbuffer*)buf;
        buffer->position = position;
    }
}

// return position
int if_buffer_position(void *buf) {
    if (!buf) {
        return -1;
    } else {
        ifbuffer *buffer = (ifbuffer*)buf;
        return buffer->position;
    }
}
// return limit
int if_buffer_limit(void *buf) {
    if (!buf) {
        return -1;
    } else {
        ifbuffer *buffer = (ifbuffer*)buf;
        return buffer->limit;
    }
}
// return size
int if_buffer_size(void *buf) {
    if (!buf) {
        return -1;
    } else {
        ifbuffer *buffer = (ifbuffer*)buf;
        return buffer->size;
    }
}

static char* if_buffer_str_cat(char *dst, char *str) {
    return strcat(dst, str);
}

// print hex
void if_buffer_printHex(void *buf) {
#ifndef IFCLIENT_ENABLE_DEBUG
	return;
#endif
    if (!buf) {
        return;
    } else {
        int i;
        char tmp[4] = {0};
        ifbuffer *buffer = (ifbuffer*)buf;
        byte *data = buffer->data + buffer->position;
        int length = buffer->limit - buffer->position;
		char *dst = (char*) malloc (sizeof(char) * length * 4);
		memset(dst, 0, sizeof(char) * length * 4);
        for (i = 0; i < length; i++) {
            if (i == 0) {
                sprintf(tmp, "%02x", buffer->data[i]);
                if_buffer_str_cat(dst, tmp);
            } else if (i % 16 == 0) {
                sprintf(tmp, "\n%x", buffer->data[i]);
                if_buffer_str_cat(dst, tmp);
            } else {
                sprintf(tmp, " %02x", buffer->data[i]);
                if_buffer_str_cat(dst, tmp);
            }
        }
		logD("%s", dst);
		free(dst);
    }
}

